import {Native} from './native.js';
import {http} from "./http.js";

/**
 * 状态栏样式枚举
 * @enum {string}
 * @readonly
 * @see os#setStateBarStyle
 */
const StateBarStyle = {
    /** 文字和图标为黑色*/
    DEFAULT: "default",
    /** 文字和图标为白色*/
    LIGHT: "light"
};

/**
 * 可分享到的第三方平台可选项
 * @enum {string}
 * @readonly
 * @see os#shareWebPage
 */
const ShareTargets = {
    /** 文字和图标为黑色*/
    WX_TIMELINE: "wx_timeline", // 微信朋友圈
    WX_SESSION: "wx_session", // 微信联系人
    WX_FAVORITE: "wx_favorite", // 微信收藏夹
};

/**
 * 系统相关操作
 * @version 4
 * @static
 * @author GuoHua Liu
 * @copyright Copyright © 2019 GuoHua Liu. All rights reserved.
 */
class os {

    /**
     * @private
     * @param {string} name
     * @param {function} onevent
     * @param {*} context
     */
    static addObserver(name, onevent, context) {
        Native.getInstance().addObserver("os/" + name, onevent, context)
        return this;
    }

    /**
     * @private
     * @param {string} name
     * @param {function} onevent
     */
    static  removeObserver(name, onevent) {
        Native.getInstance().delObserver("os/" + name, onevent)
        return this;
    }

    /**
     * 添加观察者：H5页面重新回到前台
     * @param {function} onevent
     * @param {*} context
     */
    static addResumeObserver(onevent, context = null) {
        os.addObserver("resume", onevent, context)
    }

    static removeResumeObserver(onevent) {
        os.removeObserver("resume", onevent)
    }


    static addBackKeyDownObserverA(onevent, context = null) {
        os.addObserver("backKeyDown", onevent, context)
    }

    static removeBackKeyDownObserverA(onevent) {
        os.removeObserver("backKeyDown", onevent)
    }


    static exitA() {
        Native.getInstance().callNative("os", {"method": "exit"})
    }

    static moveTaskToBackA() {
        Native.getInstance().callNative("os", {"method": "moveTaskToBack"})
    }


    /**
     * 支持浏览器:是<br>
     * 判断是否在Hos环境中
     * @returns {Boolean} 浏览器返回false，Hos环境返回true
     **/

    static isHos() {
        if(os.isIOS()) {
            return true
        }
        return os.isAndroid();
    }

    /**
     * 支持浏览器:是<br>
     * 是否运行在iOS系统中
     * @returns {Boolean} iOS返回true，非iOS返回false
     */
    static isIOS() {
        return Native.getInstance().isIOS();
    }

    /**
     * 支持浏览器:是<br>
     * 是否运行的安卓系统中
     * @returns {Boolean} 安卓返回true，非安卓返回false
     */
    static isAndroid() {
        return Native.getInstance().isAndroid();
    }

    /**
     * 获取版本号（apk/ipa版本号+H5资源版本号）
     * @return {string} 返回6位的版本号
     */
     static versionNumber() {
        if (os.isIOS()) return os.localInfo().IPA.version + "-" + os.localInfo().H5.version
        if (os.isAndroid()) return os.localInfo().APK.version + "-" + os.localInfo().H5.version
        return  "0.0.0-0.0.0";
     }

     /**
      * 支持浏览器:否，被转为alert弹出<br>
      * 弹出Toast
      * @param {string} msg
      * @param {number|undefined} time 显示时间，单位秒
      */
    static makeToast(msg, time = 1) {
        let t = time ? time : 1;
        if (os.isHos()) {
            Native.getInstance().callNative("toast", {"msg":msg + "", "time":t}, false,()=>{}, ()=>{})
            return
        }
        console.log("[os.makeToast]" + msg);
    }

    /**
     * 支持浏览器:否，浏览器会返回0.0.0.0<br>
     * 获取WiFi的ip地址，更多的WiFi操作请用Wifi类
     * @returns {String} 返回WiFi的ip地址，失败返回0.0.0.0
     */
    static ip() {
        if(this.isHos()) {
            return Native.getInstance().exec("ip");
        }
        return "0.0.0.0";
    }

    /**
     * 支持浏览器:是<br>
     * 格式化字符串
     * @param {String} formater 比如"name={0},age={1}"
     * @param {Array} args 用于替换模板中对应位置的字符串，比如["黑猫警长",8]
     */
    static format (formater, args) {
        let result = formater;
        if (arguments.length < 2) {
            return result;
        }
        let data = args;
        for ( var key in data) {
            var value = data[key];
            if (undefined != value) {
                result = result.replaceAll("\\{" + key + "\\}", value)
            }
        }
        return result;
    }

    /**
     * 支持浏览器:否，被reject<br>
     * 发送什么回复什么
     * @param {object} request 发送的内容，正常情况下也会回复该消息
     * @returns {Promise} 错误码列表：
     * - -1 环境不支持
     * - 其他 未知错误
     */
    static echo(request) {
        return new Promise((resolve,reject)=>{
            if (os.isHos()) {
                Native.getInstance().callNative("echo", request, true, resolve, reject);
            } else {
                reject({errMsg:"当前环境不支持", errCode:-1})
            }
        })
    }

    /**
     * 支持浏览器:是<br>
     * 读取文件的所有的内容，以文本的方式返回。如果出错，将返回null。
     * @param {string} path
     * @returns {string|null} 文件文本
     */
    static cat(path) {
        try {
            let xhr = new XMLHttpRequest();
            xhr.open('get', path, false)
            xhr.send(null)
            if (xhr.status === 200 || (xhr.status === 0 && xhr.responseText)) {
                return xhr.responseText
            }
        } catch (e) {
            console.error("加载" + path + "异常:" + e)
        }
        return null
    }

    /**
     * 支持浏览器:否<br>
     * @param {{url:string, version:string, describe:string}} option
     */
    static upgrade(option) {
        Native.getInstance().callNative("upgrade",
            {"url":option.url, "version": option.version, "describe":option.describe , "method":"upgrade"})
    }

    /**
     * 支持浏览器:否，浏览器调用被忽略，不报错<br>
     * @since 2
     * @param {StateBarStyle} style
     * @example os.setStateBarStyle(StateBarStyle.LIGHT)
     * @see StateBarStyle
     */
    static setStateBarStyle(style) {
        if (os.isIOS) {
            Native.getInstance().callNative("os", {"method":"setStateBarStyle", "style":style})
        }
    }

    /**
     * 支持浏览器:否，浏览器调用被忽略，不报错<br>
     * @since 3
     * @param  {string} image 请传输pick获取到图片url
     * @param  {ShareTargets} shareTarget 指定分享到的第三方平台
     */
    static shareImage(image, shareTarget = undefined) {
        if (os.isHos()) {
           return  Native.getInstance().callNative("os", {"method":"shareImage", "image":image, "to" : shareTarget})
        }
        console.log("分享图片:" + image)
    }

    /**
     * 支持浏览器:否，浏览器调用被忽略，不报错<br>
     * @since 3
     * @param text {string} 需要分享的文本
     */
    static shareText(text) {
        if (os.isHos()) {
            return  Native.getInstance().callNative("os", {"method":"shareText", "text":text})
        }
        console.log("分享文本:" + text)
    }

    /**
     * 支持浏览器:否，浏览器调用被忽略，不报错<br>
     * @since 3
     * @param  {string} url 需要分享的连接
     * @param  {string} title 文章标题
     * @param  {string} description 文章描述
     * @param  {string} thumbBmpURL 图片URL(网络图片)
     * @param  {ShareTargets} shareTarget 指定分享目标
     */
    static shareWebPage(url, title = undefined, description = undefined, thumbBmpURL = undefined, shareTarget = undefined) {
        if (os.isHos()) {
            return  Native.getInstance().callNative("os", {"method":"shareWebPage", "url":url, "title": title, "description" : description, "thumbBmpURL":thumbBmpURL, to:shareTarget})
        }
        console.log("分享网页:" + url)
    }

    /**
     * @typedef EdgeInsets
     * @property {number} top
     * @property {number} bottom
     * @property {number} left
     * @property {number} right
     */

    /**
     * 获取布局的安全距离
     * @returns {EdgeInsets} 屏幕布局的安全区
     */
    static layoutSafeArea() {
        if (os.isIOS()) {
           return Native.getInstance().syncCallNative("os", {"method":"layoutSafeArea"})
        }
        return {top:20, bottom:0, left:0, right:0}
    }

    /**
     * 打开app设置界面
     */
    static openSetting() {
        if (os.isHos()) {
            return Native.getInstance().syncCallNative("os", {"method":"openSetting"})
        }
    }

    /**
     * 开关硬件加速,主要是为了避开安卓的一些渲染问题.
     * @param enable {boolean} - true 使用硬件加速 - false 关闭硬件加速
     */
    static enableHardware(enable = true) {
        if (os.isAndroid()) {
            Native.getInstance().syncCallNative("os", {"method":"enableHardware", "enable" : enable})
        }
    }

    /**
     * 控制屏幕是否常亮
     * @param enable {boolean} - true 保持屏幕常亮 - false 关闭屏幕常亮
     */
    static enableKeepScreenOn(isKeepScreenOn = true) {
        Native.getInstance().syncCallNative("os", {"method":"enableKeepScreenOn", "isKeepScreenOn" : isKeepScreenOn})
    }

    /**
     * 获取本地信息
     @returns {
         {APK:{ version: string,describe: string,URL: string},
          IPA:{ version: string,describe: string},
          H5 :{ version: string, zipURL: string, jsonURL: string}
        }
    }*/
    static localInfo() {
        if (!os.__local) {
            let local = os.cat("static/dist.json");
            if (!local) {
                console.log("[os]从/dist.json获取本地本部信息")
                local = os.cat("dist.json");
            } else {
                console.log("[os]从/static/dist.json获取本地本部信息")
            }
            // alert(JSON.stringify(local))
            if (!local) {
                alert("dist.json不存在")
                return os.__local;
            }

            try {
                os.__local = JSON.parse(local)
            } catch (e) {
                console.log("dist.json格式错误" + e)
            }
        }
        return os.__local
    }

    /**
     * 获取当前时间戳（MS）
     * @return {number}
     */
    static timestamp() {
        return (new Date()).getTime()
    }

    /**
     * 获取当前时间戳（S）
     * @return {number}
     */
    static time() {
        let str = "" +  (new Date()).getTime() / 1000.0
        return Number(str.split(".")[0])
    }

    /**
     * 判断是否为测试模式
     * @return {boolean}
     * - true 当前处于测试模式
     * - false 当前为正常模式
     */
    static isTestMode() {
        return os.__isTestMode
    }

    /**
     * 打开测试模式，一旦打开，即使远程的dist.json的push标志为false，依然会执行更新检查。
     * - 该方法是配合push标志使用的，在更新服务器文件之前，先将服务器dist.json的push标志为false，更新完文件，内部
     *   测试人员使用旧版本打开该模式并更新资源进行测试，没问题，才将push标志为true，这时候正常用户才会进行下载更新，
     *   这样可以避免新资源推送到用户手上出现问题。
     * - 可以设置一个暗操作，比如点击版本号就调用这个方法，连续点击版本就可以打开测试模式，只有内部测试人员知道这个操作
     *
     * @param {boolean} force
     * - true 马上打开
     * - false(default) 需要连续调用4次调用才会开启
     * @return {boolean}
     * - true 打开成功
     * - false 尚未打开
     */
    static openTestMode(force = false) {

        if (os.__isTestMode || force) {
            os.__testModeCount = 0
            os.__isTestMode = true
            console.log("[os]测试模式已经打开")
            os.startUpgradeCheck()
            return os.__isTestMode
        }
        let now = os.timestamp();
        let outTime = now - os.__testModeLastTime
        if (outTime > 2000) {
            console.log("[os]打开测试时间间隔" + outTime)
            os.__testModeCount = 1
            os.__testModeLastTime = now;
            return os.__isTestMode
        }
        os.__testModeCount++;
        if (os.__testModeCount > 3) {
            os.__testModeCount = 0
            os.__isTestMode = true
            console.log("[os]测试模式已经打开")
            os.startUpgradeCheck()
            return os.__isTestMode
        }
        os.__testModeLastTime = now
        console.log("[os]尝试打开测试模式" + os.__testModeCount)
        return os.__isTestMode
    }

    /**
     * 使能/关闭更新活动（建议在进入首页的时候使能，在进入第二级页面的时候，也就是不是首页的时候关闭，
     * 特别是有编辑活动/支付等重要的页面，一定要关闭，一定要关闭，一定要关闭）
     * @param {boolean} enable
     * - true(default) 运行运行在合适的时机进行版本检查和更新
     * - false 关闭版本检查和更新
     */
    static enableUpgrade(enable = true) {
        os.__enableUpgrade = enable
    }

    /**
     * 获取远程信息
     * @returns {
         {push:boolean,
          APK:{ version: string,describe: string,URL: string},
          IPA:{ version: string,URL: string, infoURL:string},
          H5 :{ version: string, zipURL: string, jsonURL: string}
        } | null
    }*/
    static remoteInfo() {
        if (!os.__remote) return null;
        return os.__remote;
    }

    static startUpgradeCheck() {
        if (os.__versionCheckTimer) {
            clearInterval(os.__versionCheckTimer)
            os.__versionCheckTimer = null;
        }
        try {
            os.__startVersionCheck();
        } catch (e) {
            console.error("更新异常" + e)
        }
    }

    /**
     * 三位字符格式的版本号转化为整型的版本号
     * @param {string} versionString 三位的版本号比如"1.0.0"
     * @requires {number}
     */
    static v2i(versionString) {
        let arr = versionString.split(".")
        return Number(arr[0]) * 1000 * 1000 + Number(arr[1]) * 1000 + Number(arr[2]);
    }

    /**
     * @private
     */
    static  __startVersionCheck() {

        let now = os.timestamp();
        if ((now - os.__upgradeCheckLastTime) < 1000 * 10 && !os.__isTestMode) {
            console.log("[os]更新检查太频繁，本次被忽略")
            return
        }

        os.__upgradeCheckLastTime = now;

        console.log("[os]开始更新检查")


        let url = os.localInfo().H5.jsonURL + "?t=" + os.timestamp()
        console.log("[os]加载" + url)

        http.get(url, {}, {}).then((resp)=>{

            os.__remote = resp;

            if (!os.remoteInfo().push) {
                console.log("[os]远程未开始推送:" + JSON.stringify(os.localInfo()) + "|" + JSON.stringify(os.remoteInfo()))
                if (!os.__isTestMode) {
                    console.log("[os]放弃更新")
                    return
                }
                console.log("[os]因为处于测试模式，因此继续尝试更新")
            }

            let isUpdateBin = false
            let isUpgradeH5

            if (os.isAndroid()) {
                let v1 = os.v2i(os.localInfo().APK.version)
                let v2 = os.v2i(os.remoteInfo().APK.version)
                if (v2 > v1) {
                    isUpdateBin = true
                    console.log("[os]请求更新安卓到版本" + v2)
                    os.upgrade({url:os.remoteInfo().APK.URL, describe:os.remoteInfo().APK.describe,
                        version:os.remoteInfo().APK.version})
                } else {
                    console.log("[os]安卓已经是最新版本" + v1)
                }
            }

            if (os.isIOS()) {
                let v1 = os.v2i(os.localInfo().IPA.version)
                let v2 = os.v2i(os.remoteInfo().IPA.version)
                if (v2 > v1) {

                    isUpdateBin = true
                    console.log("[os]iOS可能可以更新到" + v2)
                } else {
                    console.log("[os]iOS已经是最新版本" + v1)
                }
            }

            if (!isUpdateBin) {
                let v1 = os.v2i(os.localInfo().H5.version)
                let v2 = os.v2i(os.remoteInfo().H5.version)
                if (v2 > v1) {
                    console.log("[os]资源发现新版本:" + JSON.stringify(os.localInfo()) + "|" + JSON.stringify(os.remoteInfo()))
                    isUpgradeH5 = (os.isAndroid() && os.localInfo().APK.version === os.remoteInfo().APK.version)  ||
                                  (os.isIOS() && os.localInfo().IPA.version === os.remoteInfo().IPA.version)
                    if (isUpgradeH5) {
                        console.log("[os]请求资源更新到" + v2)
                        os.upgrade({url:os.remoteInfo().H5.zipURL, version:os.remoteInfo().H5.version})
                    } else {
                        console.log("[os]当前环境无法使用该资源，放弃资源更新")
                    }
                } else {
                    console.log("[os]资源已经是最新")
                }
            }
        }, (error)=>{
            console.log("[os]加载远程dist.json失败，" + error);
        });
    }

}

os.__testModeCount = 0;
os.__testModeLastTime = 0;
os.__upgradeCheckLastTime = 0;
os.__enableUpgrade = true

// APP启动后马上执行一次检查
os.startUpgradeCheck()

setTimeout(()=>{}, 50 * 1000)

// 每次回到前台执行一次检查
os.addResumeObserver(()=>{
    if (os.__enableUpgrade) {
        os.startUpgradeCheck()
    }
})

export {os, StateBarStyle, ShareTargets}
